using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Andshev.OrmTools.Linq2Query.Attributes;
using Andshev.OrmTools.Linq2Query.Exceptions;
using Andshev.OrmTools.Linq2Query.Tools;

namespace Andshev.OrmTools.Linq2Query
{
    public class OrmContext
    {
        protected Dictionary<Type, string> TableMappings { get; set; }
        protected List<ForeignMapping> ForeignMappings { get; set; }

        public OrmContext()
        {
            TableMappings = new Dictionary<Type, string>();
            ForeignMappings = new List<ForeignMapping>();
        }

        public string GetTableName<T>()
        {
            return TableMappings[typeof(T)];
        }

        public ForeignMapping GetForeignMapping(Type type, string propertyName)
        {
            return ForeignMappings
                .Where(fm => fm.MasterType == type && fm.PropertyName == propertyName)
                .SingleOrDefault();
        }

        public void RegisterEntity<T>()
        {
            TableMappingAttribute tableMappingAttribute = ReflectionTool.GetAttribute<T, TableMappingAttribute>();

            if (tableMappingAttribute == null)
                throw new OrmContextException("Specified class has no TableMappingAttribute");

            TableMappings[typeof(T)] = tableMappingAttribute.TableName;
        }

        public void BuildForeignMappings()
        {
            foreach (Type type in TableMappings.Keys)
            {
                foreach (PropertyInfo dataColumn in ReflectionTool.GetForeignEntityColumns(type))
                {
                    ForeignEntityAttribute foreignEntityAttribute =
                        ReflectionTool.GetAttribute<ForeignEntityAttribute>(dataColumn);
                    ForeignMapping foreignMapping = new ForeignMapping()
                    {
                        MasterType = type,
                        PropertyName = dataColumn.Name,
                        MasterTableName = TableMappings[type],
                        MasterColumnName = foreignEntityAttribute.ColumnName,
                        ForeignColumnName = foreignEntityAttribute.ForeignColumnName,
                        ForeignTableName = TableMappings[dataColumn.PropertyType]
                    };

                    ForeignMappings.Add(foreignMapping);
                }
            }
        }
    }
}